<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>this绑定规则三-new绑定(This binding rule three - new binding)</title>
  <!-- 
  在JavaScript中， `this` 关键字的行为受到多种规则的影响。其中，新绑定（New Binding）是第三个重要的规则。新绑定指的是当一个函数作为构造函数被调用时， `this` 的值指向新创建的实例对象。
  一、新绑定的定义
  新绑定是指当一个函数使用 `new` 关键字被调用时， `this` 会绑定到新创建的对象实例上。构造函数通常用于创建对象，并且可以通过 `new` 关键字来调用。

  二、新绑定的实现
  1. 使用构造函数：
    - 当使用 `new` 关键字调用一个函数时，JavaScript会执行以下步骤：
      - 创建一个新对象。
      - 将新对象的 `__proto__` 属性指向构造函数的原型。
      - 执行构造函数中的代码， `this` 指向新对象。
      - 如果构造函数没有显式返回对象，则返回新创建的对象。
    function Person(name) {
      this.name = name; // this指向新创建的对象
    }

    const alice = new Person('Alice');
    console.log(alice.name); // 输出: Alice
  在这个例子中， `Person` 是一个构造函数，使用 `new` 关键字创建了一个新对象 `alice` ， `this` 指向 `alice` 。

  2. 构造函数的原型：
    - 新创建的对象的 `__proto__` 属性指向构造函数的 `prototype` 属性，从而可以访问原型上的方法和属性。
    Person.prototype.greet = function() {
      console.log(`Hello, my name is ${this.name}`);
    };

    alice.greet(); // 输出: Hello, my name is Alice
  在这个例子中， `greet` 方法被添加到 `Person` 的原型上， `alice` 可以调用这个方法， `this` 指向 `alice` 。

  三、新绑定的注意事项
  1. 返回值：
    - 如果构造函数显式返回一个对象， `new` 表达式将返回这个对象；如果返回的是非对象类型（如基本数据类型），则返回新创建的对象。

      示例：
    function Person(name) {
      this.name = name;
      return { greeting: 'Hello' }; // 返回一个对象
    }

    const bob = new Person('Bob');
    console.log(bob.name); // 输出: Bob
    console.log(bob.greeting); // 输出: undefined
  在这个例子中，尽管构造函数返回了一个对象，但 `bob` 仍然是新创建的对象， `name` 属性在 `bob` 上可用，而返回的对象的属性不可用。

  2. 构造函数的命名约定：
    - 通常，构造函数的名称以大写字母开头，以便与普通函数区分。

  四、总结
  - 新绑定是指当一个函数作为构造函数使用 `new` 关键字调用时， `this` 指向新创建的对象实例。
  - 使用 `new` 关键字时，JavaScript会创建一个新对象并将其 `__proto__` 指向构造函数的原型。
  - 如果构造函数返回一个对象，则返回该对象；否则返回新创建的对象。
   -->
</head>

<body>

  <script>
    const obj = {
      name: "Alice",
      greet: function () {
        console.log(`Hello, my name is ${this.name}`);
      }
    }

    // 1. new函数手动实现
    function createNew(constructor, ...args) {
      // 创建一个新对象
      const obj = {};
      // 将新对象的__proto__指向构造函数的原型
      // Object.setPrototypeOf(obj, constructor.prototype);
      obj.__proto__ = constructor.prototype;

      // 手动实现apply函数
      Function.prototype.myApply = function (context, args) {
        // 1. 判断context是否为null或者undefined，如果是，则将context指向全局对象
        context = context || window;
        // 2. 创建一个唯一的函数名
        const fnSymbol = Symbol();
        // 3. 将函数赋值给context的属性
        context[fnSymbol] = this;
        // 4. 调用函数并传入参数
        const result = context[fnSymbol](...args);
        // 5. 删除context的属性
        delete context[fnSymbol];
        // 6. 返回函数调用的结果
        return result;
      };

      // 调用构造函数，并将新对象作为this
      const result = constructor.myApply(obj, args);

      // 如果构造函数返回一个对象，则返回该对象；否则返回新创建的对象
      return result instanceof Object ? result : obj;
    }

    // 2. new绑定
    function Person(name) {
      this.name = name;
      console.log("Person", this);
    }

    const bob = new Person('Bob');
    console.log(bob.name); // 输出: Bob

    const bob2 = createNew(Person, obj);
    console.log(bob2.name); // 输出: coderliang






  </script>

</body>

</html>